/*
 * Copyright (c) 2009-2010 HIT Microelectronic Center
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * Authors: Gou Pengfei
 *
 * Date:    May. 2010
 *
 */
#ifndef __CPU_EDGE_OPN_PKT_HH__
#define __CPU_EDGE_OPN_PKT_HH__

#include <deque>

#include "base/statistics.hh"
#include "base/fast_alloc.hh"
#include "base/refcnt.hh"
#include "config/the_isa.hh"
#include "arch/faults.hh"

template<class Impl>
class OpnPktInfo
{
  public :
    typedef TheISA::OpSize OpSize;

    /** pid not used so far. */
    uint64_t pid;

    /** Thread id this pakcet belongs to. */
    ThreadID tid;

    /** Destnation of this packet. */
    int destID;
    int destX;
    int destY;

    /** Source of this packet. */
    int srcID;
    int srcX; 
    int srcY; 

    /** Sender of this packet. */
    int senderID;
    int senderX;
    int senderY;

    /** Receiver of this packet. */
    int recverID;
    int recverX;
    int recverY;

    /** Block id of this packet. */
    TheISA::BlockID blockID;

    /** Not used so far. */
    bool opBypass;

    /** Slot id in local IQ. */
    unsigned iqSlotID;

    /** Id of frame this packet belongs to. */
    unsigned frameID;

    /** Consumer type of this packet. */
    uint8_t consumerType;

    /** Consumer subtype of this packet. */
    uint8_t consumerSubType;

    /** Data flow token type of this packet. */
    uint8_t tokenType;

    /** Data of this packet. */
    OpSize data;

    /** Fault pointer of this packet, if any. */
    Fault fault;

    /** Inject time in tickes. */
    UTick injTime; 

    /** Arrival time in tickes. */
    UTick arrTime;

    //remote_bypass_type_t remote_bypass_type;

    OpnPktInfo():fault(NoFault) {}
    
    inline void copyFrom (OpnPktInfo *h)
    {
        pid = h->pid;
        tid = h->tid;
        
        destID = h->destID;
        destX = h->destX;
        destY = h->destY;
        srcID = h->srcID;
        srcX = h->srcX;
        srcY = h->srcY;

        senderID = h->senderID;
        senderX = h->senderX;
        senderY = h->senderY;

        recverID = h->recverID;
        recverX = h->recverX;
        recverY = h->recverY;

        blockID = h->blockID;
        opBypass = h->opBypass;
        iqSlotID = h->iqSlotID;
        frameID = h->frameID;
        consumerType = h->consumerType;
        consumerSubType = h->consumerSubType;
        tokenType = h->tokenType;
        fault = h->fault;
        
        data = h->data;

        injTime = h->injTime;
        arrTime = h->arrTime;
    };

};

template<class Impl>
class EdgeOpnPkt : public FastAlloc, public RefCounted 
{
  public:
    typedef typename Impl::CPUPol CPUPol;
    typedef typename CPUPol::Execute Execute; 
    typedef typename CPUPol::OpnPktPtr OpnPktPtr;
    typedef typename Impl::DynInstPtr DynInstPtr;
    typedef typename std::list<OpnPktPtr>::iterator OpnPktListIt;
    typedef TheISA::Dir_t Dir_t;
    typedef TheISA::FlitType_t FlitType_t;
    
    bool valid;
    bool credit;
    bool squashed;
    FlitType_t flitType;
    UTick winjTime;

    OpnPktInfo<Impl> *info;

    /** Pointer to execute stage this pkt belongs to. */
    Execute *executeStage;

    /** An iterator of the packet itself. */
    OpnPktListIt pktIt;

    EdgeOpnPkt(Execute * exe_ptr): executeStage(exe_ptr) 
    { 
        valid = false;
        credit = false;
        squashed = false;
        info = new OpnPktInfo<Impl>();

#ifndef NDEBUG
        executeStage->opnPktCount ++;
        if (executeStage->opnPktCount > 1500) {
            assert(executeStage->opnPktCount <= 1500);
        }
#endif
    }
    
    ~EdgeOpnPkt() 
    {
        //info->inst = NULL;
        delete info;

#ifndef NDEBUG
        executeStage->opnPktCount --;
#endif
    }

    inline void copyFrom (OpnPktPtr &p) 
    {
        assert(p->info);
        
        valid = p->valid;
        squashed = p->squashed;
        flitType = p->flitType;
        winjTime = p->winjTime;
        pktIt = p->pktIt;
        
        info->copyFrom (p->info);
    } 
};

#endif //__CPU_EDGE_OPN_PKT_HH__
